#include <jni.h>
#include <time.h>
#include <android/log.h>
#include <android/bitmap.h>

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define  LOG_TAG    "libnativebuffer"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

/* Set to 1 to enable debug log traces. */
#define DEBUG 0

JNIEXPORT jint JNICALL Java_pl_polidea_nativebuffer_NativeBuffer_setIntData(JNIEnv *env,jobject obj, jintArray array,jint length){
	void *data = malloc(length*sizeof(int));
	(*env)->GetIntArrayRegion(env, array, 0,length, (jint *)data);
	return data;
}

JNIEXPORT jint JNICALL Java_pl_polidea_nativebuffer_NativeBuffer_setBitmapData2(JNIEnv *env,jobject obj, jobject bitmap){
    AndroidBitmapInfo info;
    void *pixels;
    int ret;

    if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
        LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
        return;
    }

    if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
        LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
    }

	int length = info.stride*info.height;
    void *data = malloc(length*sizeof(int));
	memcpy(data,pixels,length);

    AndroidBitmap_unlockPixels(env, bitmap);

	return data;
}

JNIEXPORT jint JNICALL Java_pl_polidea_nativebuffer_NativeBuffer_setData(JNIEnv *env,jobject obj, jbyteArray array,jint length){
	void *data = malloc(length);
	(*env)->GetByteArrayRegion(env, array, 0,length, (jbyte *)data);
	return data;
}

JNIEXPORT jintArray JNICALL Java_pl_polidea_nativebuffer_NativeBuffer_getIntData(JNIEnv * env, jobject  obj, jint pointer,jint length){
	jintArray array = (*env)->NewIntArray(env,length);
	(*env)->SetIntArrayRegion(env, array, 0,length, (jint *)pointer);
	return array;
}

JNIEXPORT void JNICALL Java_pl_polidea_nativebuffer_NativeBuffer_getBitmapData2(JNIEnv * env, jobject  obj, jint pointer, jobject bitmap){
    AndroidBitmapInfo info;
    void *pixels;
    int ret;

    if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
        LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
        return;
    }

    if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
        LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
    }

	int length = info.stride*info.height;
    void *data = (void*)pointer;
	memcpy(pixels,data,length);

    AndroidBitmap_unlockPixels(env, bitmap);
}

JNIEXPORT jbyteArray JNICALL Java_pl_polidea_nativebuffer_NativeBuffer_getData(JNIEnv * env, jobject  obj, jint pointer,jint length){
	jbyteArray array = (*env)->NewByteArray(env,length);
	(*env)->SetByteArrayRegion(env, array, 0,length, (jbyte *)pointer);
	return array;
}

JNIEXPORT void JNICALL Java_pl_polidea_nativebuffer_NativeBuffer_free2(JNIEnv * env, jobject  obj, jint pointer){
	free((void*)pointer);
}

JNIEXPORT jint JNICALL Java_pl_polidea_nativebuffer_NativeBuffer_getMemFree(JNIEnv * env, jobject  obj) {
	FILE *meminfo = fopen("/proc/meminfo", "r");
    if(meminfo == NULL)
        return -1;

    char line[256];
    while(fgets(line, sizeof(line), meminfo))
    {
        int ram;
        if(sscanf(line, "MemFree: %d kB", &ram) == 1)
        {
            fclose(meminfo);
            return ram;
        }
    }

    // If we got here, then we couldn't find the proper line in the meminfo file:
    // do something appropriate like return an error code, throw an exception, etc.
    fclose(meminfo);
    return -1;
}

JNIEXPORT jint JNICALL Java_pl_polidea_nativebuffer_NativeBuffer_getMemTotal(JNIEnv * env, jobject  obj) {
	FILE *meminfo = fopen("/proc/meminfo", "r");
    if(meminfo == NULL)
        return -1;

    char line[256];
    while(fgets(line, sizeof(line), meminfo))
    {
        int ram;
        if(sscanf(line, "MemTotal: %d kB", &ram) == 1)
        {
            fclose(meminfo);
            return ram;
        }
    }

    // If we got here, then we couldn't find the proper line in the meminfo file:
    // do something appropriate like return an error code, throw an exception, etc.
    fclose(meminfo);
    return -1;
}
